﻿/********************************************************
 * Module Name    : Scheduler
 * Purpose        : Schedule the Events
 * Author         : Karan
 * Date           : 25-May-2011
 ******************************************************/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.SqlClient;
using System.Data;
using VAdvantage.Process; using VAdvantage.ProcessEngine;
using VAdvantage.DataBase;
using VAdvantage.Utility;
using VAdvantage.Classes;
using VAdvantage.Logging;
using VAdvantage.Print;
using VAdvantage.Model;


namespace VAdvantage.Model
{
    public class MScheduler : X_AD_Scheduler, ViennaProcessor
    {
        /// <summary>
        /// Get Active
        /// </summary>
        /// <param name="ctx">context</param>
        /// <returns>active processors</returns>
        public static MScheduler[] GetActive(Ctx ctx)
        {
            List<MScheduler> list = new List<MScheduler>();
            String sql = "SELECT * FROM AD_Scheduler WHERE IsActive='Y'";
            try
            {
                DataSet ds = DB.ExecuteDataset(sql,null,null);
                foreach (DataRow dr in ds.Tables[0].Rows)
                {
                    list.Add(new MScheduler(ctx, dr, null));
                }
                ds = null;
            }
            catch (Exception e)
            {
                
                s_log.Log(Level.SEVERE, sql, e);
            }


            MScheduler[] retValue = new MScheduler[list.Count()];
            retValue = list.ToArray();
            return retValue;
        }	//	getActive

        	/**	Static Logger	*/
        private static VLogger s_log = VLogger.GetVLogger(typeof(MScheduler).FullName);

        /// <summary>
        /// Standard Constructor
        /// </summary>
        /// <param name="ctx">context</param>
        /// <param name="AD_Scheduler_ID">scheduler id</param>
        /// <param name="trxName">optional transaction name</param>
        public MScheduler(Ctx ctx, int AD_Scheduler_ID, String trxName)
            : base(ctx, AD_Scheduler_ID, trxName)
        {
            
            if (AD_Scheduler_ID == 0)
            {
                //	setAD_Process_ID (0);
                //	setName (null);
                SetFrequencyType(FREQUENCYTYPE_Day);
                SetFrequency(1);
                //
                SetKeepLogDays(7);
                //	setSupervisor_ID (0);
            }
        }	//	MScheduler


        /// <summary>
        /// Load Constructor
        /// </summary>
        /// <param name="ctx">context</param>
        /// <param name="rs">datarow</param>
        /// <param name="trxName">optional transaction name</param>
        public MScheduler(Ctx ctx, DataRow rs, String trxName)
            : base(ctx, rs, trxName)
        {
        }	//	MScheduler

        /** Process to be executed		*/
        private MProcess m_process = null;
        /**	Scheduler Parameter			*/
        private MSchedulerPara[] m_parameter = null;
        /** Scheduler Recipients		*/
        private MSchedulerRecipient[] m_recipients = null;

        /// <summary>
        /// Get Server ID
        /// </summary>
        /// <returns>ID</returns>
        public String GetServerID()
        {
            return "Scheduler" + Get_ID();
        }	//	getServerID

        /// <summary>
        /// Get Date Next Run
        /// </summary>
        /// <param name="requery">requery</param>
        /// <returns>date next run</returns>
        public DateTime? GetDateNextRun(bool requery)
        {
            if (requery)
                Load(Get_TrxName());
            return GetDateNextRun();
        }	//	getDateNextRun


        /// <summary>
        /// Get Logs
        /// </summary>
        /// <returns>logs</returns>
        public ViennaProcessorLog[] GetLogs()
        {
            List<MSchedulerLog> list = new List<MSchedulerLog>();
            String sql = "SELECT * "
                + "FROM AD_SchedulerLog "
                + "WHERE AD_Scheduler_ID=@scheduleid "
                + "ORDER BY Created DESC";
           
            try
            {
                SqlParameter[] param = new SqlParameter[1];
                param[0] = new SqlParameter("@scheduleid", GetAD_Scheduler_ID());
                DataSet ds = DB.ExecuteDataset(sql, param);

                foreach (DataRow dr in ds.Tables[0].Rows)
                {
                    list.Add(new MSchedulerLog(GetCtx(), dr, Get_TrxName()));
                }
                ds = null;
            }
            catch (Exception e)
            {
               
                log.Log(Level.SEVERE, sql, e);
            }


            MSchedulerLog[] retValue = new MSchedulerLog[list.Count()];
            retValue = list.ToArray();
            return retValue;
        }	//	getLogs
          

        /// <summary>
        /// Delete old Request Log
        /// </summary>
        /// <returns>number of records</returns>
        public int DeleteLog()
        {
            if (GetKeepLogDays() < 1)
                return 0;
            String sql = "DELETE FROM AD_SchedulerLog "
                + "WHERE AD_Scheduler_ID=" + GetAD_Scheduler_ID()
                + " AND (Created+" + GetKeepLogDays() + ") < SysDate";
            int no = DB.ExecuteQuery(sql, null, Get_TrxName());
            return no;
        }	//	deleteLog

        /// <summary>
        /// Get Process
        /// </summary>
        /// <returns>process</returns>
        public MProcess GetProcess()
        {
            if (m_process != null)
                m_process = null;

            if (m_process == null)
                m_process = new MProcess(GetCtx(), GetAD_Process_ID(), null);
            return m_process;
        }	//	getProcess


        /// <summary>
        /// Get Parameters
        /// </summary>
        /// <param name="reload">reload</param>
        /// <returns>parameter</returns>
        public MSchedulerPara[] GetParameters(bool reload)
        {
            if (!reload && m_parameter != null)
                return m_parameter;
            List<MSchedulerPara> list = new List<MSchedulerPara>();
            String sql = "SELECT * FROM AD_Scheduler_Para WHERE AD_Scheduler_ID=@scheduleid AND IsActive='Y'";
            DataSet ds = null;
            try
            {
                SqlParameter[] param = new SqlParameter[1];
                param[0] = new SqlParameter("@scheduleid", GetAD_Scheduler_ID());
                ds = new DataSet();
                ds = DB.ExecuteDataset(sql, param);

                foreach (DataRow dr in ds.Tables[0].Rows)
                {
                    list.Add(new MSchedulerPara(GetCtx(), dr, null));
                }
                ds = null;
            }
            catch (Exception e)
            {
                if (ds != null)
                {
                    ds = null;
                }
                log.Log (Level.SEVERE, sql, e);
            }

            m_parameter = new MSchedulerPara[list.Count()];
            m_parameter = list.ToArray();
            return m_parameter;
        }	//	getParameter

        /// <summary>
        /// Get Recipients
        /// </summary>
        /// <param name="reload">reload</param>
        /// <returns>recipients</returns>
        public MSchedulerRecipient[] GetRecipients(bool reload)
        {
            if (!reload && m_recipients != null)
                return m_recipients;
            List<MSchedulerRecipient> list = new List<MSchedulerRecipient>();
            String sql = "SELECT * FROM AD_SchedulerRecipient WHERE AD_Scheduler_ID=@scheduleid AND IsActive='Y'";
            try
            {
                SqlParameter[] param = new SqlParameter[1];
                param[0] = new SqlParameter("@scheduleid", GetAD_Scheduler_ID());
                DataSet ds = DB.ExecuteDataset(sql, param);

                foreach (DataRow dr in ds.Tables[0].Rows)
                {
                    list.Add(new MSchedulerRecipient(GetCtx(), dr, null));
                }
                ds = null;

            }
            catch (Exception e)
            {
               
                log.Log(Level.SEVERE, sql, e);
            }

            m_recipients = new MSchedulerRecipient[list.Count()];
            m_recipients = list.ToArray();
            return m_recipients;
        }	//	getRecipients

        /// <summary>
        /// Get Recipient AD_User_IDs
        /// </summary>
        /// <returns>array of user IDs</returns>
        public int[] GetRecipientAD_User_IDs()
        {
            List<int> list = new List<int>();
            MSchedulerRecipient[] recipients = GetRecipients(false);
            for (int i = 0; i < recipients.Length; i++)
            {
                MSchedulerRecipient recipient = recipients[i];
                if (!recipient.IsActive())
                    continue;
                if (recipient.GetAD_User_ID() != 0)
                {
                    int ii = recipient.GetAD_User_ID();
                    if (!list.Contains(ii))
                        list.Add(ii);
                }
                if (recipient.GetAD_Role_ID() != 0)
                {
                    MUserRoles[] urs = MUserRoles.GetOfRole(GetCtx(), recipient.GetAD_Role_ID());
                    for (int j = 0; j < urs.Length; j++)
                    {
                        MUserRoles ur = urs[j];
                        if (!ur.IsActive())
                            continue;
                        int ii = ur.GetAD_User_ID();
                        if (!list.Contains(ii))
                            list.Add(ii);
                    }
                }
            }
            //	Add Updater
            if (list.Count() == 0)
            {
                int ii = GetUpdatedBy();
                list.Add(ii);
            }
            //
            int[] recipientIDs = new int[list.Count()];
            recipientIDs = list.ToArray();
            return recipientIDs;
        }	//	getRecipientAD_User_IDs


        /// <summary>
        /// String Representation
        /// </summary>
        /// <returns>info</returns>
        public override String ToString()
        {
            StringBuilder sb = new StringBuilder("MScheduler[");
            sb.Append(Get_ID()).Append("-").Append(GetName())
                .Append("]");
            return sb.ToString();
        }	//	toString


        /// <summary>
        /// Run Scheduler
        /// </summary>
        /// <param name="trx">optional transaction</param>
        /// <returns>Summary</returns>
        public String Execute(Trx trx)
        {
            GetProcess();
            if (m_process.IsReport())
            {
                return ""; // RunReport(trx); //not implemented yet
            }
            else
            {
                return RunProcess(trx);
            }
        }	//	execute

        public   void ExecuteFromThread(Trx trx)
        {
            this.Execute(trx);
        }

        /// <summary>
        /// Run Report
        /// </summary>
        /// <param name="trx">optional transaction</param>
        /// <returns></returns>
        private String RunReport(Trx trx)
        {
            log.Info(m_process.ToString());
            if (!m_process.IsReport() || m_process.GetAD_ReportView_ID() == 0)
                return "Not a Report AD_Process_ID=" + m_process.GetAD_Process_ID()
                    + " - " + m_process.GetName();
            //	Process
            int AD_Table_ID = 0;
            int Record_ID = 0;
            //
            MPInstance pInstance = new MPInstance(m_process, Record_ID);
            FillParameter(pInstance);
            //
            ProcessInfo pi = new ProcessInfo(m_process.GetName(), m_process.GetAD_Process_ID(), AD_Table_ID, Record_ID);
            pi.SetAD_User_ID(GetUpdatedBy());
            pi.SetAD_Client_ID(GetAD_Client_ID());
            pi.SetAD_PInstance_ID(pInstance.GetAD_PInstance_ID());
            if (!m_process.ProcessIt(pi, trx) && pi.GetClassName() != null)
                return "Process failed: (" + pi.GetClassName() + ") " + pi.GetSummary();

            //	Report
            ReportEngine re = ReportEngine.Get(GetCtx(), pi);
            if (re == null)
                return "Cannot create Report AD_Process_ID=" + m_process.GetAD_Process_ID()
                    + " - " + m_process.GetName();
            //File report = re.getPDF();
            //	Notice
            int AD_Message_ID = 884;		//	HARDCODED SchedulerResult
            int[] userIDs = GetRecipientAD_User_IDs();
            for (int i = 0; i < userIDs.Length; i++)
            {
                MNote note = new MNote(GetCtx(), AD_Message_ID, userIDs[i], trx.GetTrxName());
                note.SetClientOrg(GetAD_Client_ID(), GetAD_Org_ID());
                note.SetTextMsg(GetName());
                note.SetDescription(GetDescription());
                note.SetRecord(AD_Table_ID, Record_ID);
                note.Save();
                //	Attachment
                MAttachment attachment = new MAttachment(GetCtx(), X_AD_Note.Table_ID, note.GetAD_Note_ID(), trx.GetTrxName());
                attachment.SetClientOrg(GetAD_Client_ID(), GetAD_Org_ID());
                //attachment.AddEntry(report);
                attachment.SetTextMsg(GetName());
                attachment.Save();
            }
            //
            return pi.GetSummary();
        }	//	runReport


        /// <summary>
        /// Run Process
        /// </summary>
        /// <param name="trx">optional transaction</param>
        /// <returns>Summary</returns>
        private String RunProcess(Trx trx)
        {
            log.Info(m_process.ToString());
            //	Process (see also MWFActivity.performWork
            int AD_Table_ID = 0;
            int Record_ID = 0;
            //
            MPInstance pInstance = new MPInstance(m_process, Record_ID);
            if (m_process.Get_ID() <= 0)
                return "error";
            FillParameter(pInstance);
            //
            ProcessInfo pi = new ProcessInfo(m_process.GetName(), m_process.GetAD_Process_ID(), AD_Table_ID, Record_ID);
            pi.SetAD_User_ID(GetUpdatedBy());
            pi.SetAD_Client_ID(GetAD_Client_ID());
            pi.SetAD_PInstance_ID(pInstance.GetAD_PInstance_ID());
            m_process.ProcessIt(pi, trx);
            return pi.GetSummary();
        }	//	runProcess


        /// <summary>
        /// Fill the parameter
        /// </summary>
        /// <param name="pInstance">instance detail</param>
        private void FillParameter(MPInstance pInstance)
        {
            MSchedulerPara[] sParams = GetParameters(false);
            MPInstancePara[] iParams = pInstance.GetParameters();
            for (int pi = 0; pi < iParams.Length; pi++)
            {
                MPInstancePara iPara = iParams[pi];
                for (int np = 0; np < sParams.Length; np++)
                {
                    MSchedulerPara sPara = sParams[np];
                    if (iPara.GetParameterName().Equals(sPara.GetColumnName()))
                    {
                        String variable = sPara.GetParameterDefault();
                        log.Fine(sPara.GetColumnName() + " = " + variable);
                        //	Value - Constant/Variable
                        Object value = variable;
                        if (variable == null || (variable != null && variable.Length == 0))
                            value = null;
                        else if (variable.IndexOf("@") != -1)	//	we may have a variable
                        {
                            //	Strip
                            int index = variable.IndexOf("@");
                            String columnName = variable.Substring(index + 1);
                            index = columnName.IndexOf("@");
                            if (index != -1)
                            {
                                columnName = columnName.Substring(0, index);
                                //	try Env
                                String env = GetCtx().GetContext(columnName);
                                if (env.Length == 0)
                                {
                                    log.Warning(sPara.GetColumnName()
                                        + " - not in environment =" + columnName
                                        + "(" + variable + ") - ignored");
                                    break;
                                }
                                else
                                    value = env;
                            }
                        }	//	@variable@

                        //	No Value
                        if (value == null)
                        {
                            log.Fine(sPara.GetColumnName() + " - empty");
                            break;
                        }

                        //	Convert to Type
                        try
                        {
                            if (DisplayType.IsNumeric(sPara.GetDisplayType())
                                || DisplayType.IsID(sPara.GetDisplayType()))
                            {
                                Decimal? bd = null;
                                if (value is Decimal)
                                    bd = (Decimal)value;
                                else if (value is int)
                                    bd = decimal.Parse(value.ToString());
                                else
                                    bd = decimal.Parse(value.ToString());
                                iPara.SetP_Number((decimal)bd);
                                log.Fine(sPara.GetColumnName() + " = " + variable + " (=" + bd + "=)");
                            }
                            else if (DisplayType.IsDate(sPara.GetDisplayType()))
                            {
                                DateTime? ts = null;
                                if (value is DateTime)
                                    ts = (DateTime)value;
                                else
                                    ts = DateTime.Parse(value.ToString());
                                iPara.SetP_Date(ts);
                                log.Fine(sPara.GetColumnName() + " = " + variable + " (=" + ts + "=)");
                            }
                            else
                            {
                                iPara.SetP_String(value.ToString());
                                log.Fine(sPara.GetColumnName()
                                        + " = " + variable
                                        + " (=" + value + "=) " + value.GetType().FullName);
                            }
                            if (!iPara.Save())
                                log.Warning("Not Saved - " + sPara.GetColumnName());
                        }
                        catch (Exception e)
                        {
                            log.Warning(sPara.GetColumnName() + " = " + variable + " (" + value + ") " + value.GetType().FullName + " - " + e.Message);
                        }
                        break;
                    }	//	parameter match
                }	//	scheduler parameter loop
            }	//	instance parameter loop
        }	//	fillParameter

        public DateTime[] CheckProcessTime(int AD_SCHEDULE_ID, MScheduler scheduler)
        {
             MSchedule schedule = new MSchedule(GetCtx(), AD_SCHEDULE_ID, Get_TrxName());
             DateTime? dtNextRun;
             bool blNextDate = false;
             try
             {
                 dtNextRun = scheduler.GetUpdated();
                 if (schedule.GetScheduleHour() > 0)
                 {
                     //blNextDate = true;
                     dtNextRun = dtNextRun.Value.Subtract(new TimeSpan(dtNextRun.Value.Hour, 0, 0));
                     dtNextRun = dtNextRun.Value.AddHours(schedule.GetScheduleHour());
                 }
                 if (schedule.GetScheduleMinute() > 0)
                 {
                     //blNextDate = true;
                     dtNextRun = dtNextRun.Value.Subtract(new TimeSpan(0, dtNextRun.Value.Minute, 0));
                     dtNextRun = dtNextRun.Value.AddMinutes(schedule.GetScheduleMinute());
                 }
             }
             catch
             {
                 dtNextRun = DateTime.Now;

             }
            if((scheduler.GetDateNextRun() != null) && (!blNextDate))
                dtNextRun = (DateTime)this.GetDateNextRun();

            DateTime[] dtSchedule = schedule.GetNext((DateTime)dtNextRun, 1);
            DateTime[] returnValue = new DateTime[2];
            if (DateTime.Now.ToString("dd-MM-yyyy hh:mm") == dtNextRun.Value.ToString("dd-MM-yyyy hh:mm"))
            {
                returnValue[0] = DateTime.Parse(dtNextRun.ToString());
                returnValue[1] = DateTime.Parse(dtSchedule[0].ToString());

                //scheduler.SetDateLastRun(DateTime.Parse(dtNextRun.ToString()));
                //dtSchedule = schedule.GetNext(DateTime.Parse(dtSchedule[0].ToString()), 1);
                //scheduler.SetDateNextRun(DateTime.Parse(dtSchedule[0].ToString()));
                //if (!scheduler.Save())
                    //return false;
                return returnValue;
            }
            else
                return returnValue;
        }
    }
}
